#include <lib.h>
#include <armor_types.h>
#include <vendor_types.h>
#include <daemons.h>
#include "/lib/include/vendor.h"

inherit LIB_SENTIENT;
inherit "/lib/manycoins";

private static int MaxItems, VendorType, bargain;
private static string StorageRoom, LocalCurrency;
private static mapping Costs, Values;

static void create(){
    sentient::create();
    Costs = ([]);
    Values = ([]);
    LocalCurrency = "gold";
    VendorType = VT_TREASURE;
    MaxItems = 40;
}

mixed direct_buy_str_from_liv(string str){ 
    return CanSell(this_player(), str); 
}

int indirect_sell_obj_to_liv(){ return 1; }

int indirect_sell_obs_to_liv(){ return 1; }

int CanCarry(int amount){ return 1; }

mixed CanBuy(object who, object *obs){
    if( !load_object(StorageRoom) ) 
        return "There is a bug with the vendor's storage, please report it.";
    return 1;
}

mixed CanSell(object who, string what){
    if( !load_object(StorageRoom) ) 
        return "There is a bug with the vendor's storage, please report it.";
    return 1;
}

mixed eventBuy(object who, object *obs){
    object *tmp;
    object sroom, ob;
    int cost;

    sroom = load_object(StorageRoom);
    if( sizeof(all_inventory(sroom)) > GetMaxItems() ){
        eventForce("say I am having trouble getting rid of the things I "
          "have to sell right now.");
        return 1;
    }
    if( !sizeof(obs) ){
        eventForce("say you have nothing to sell!");
        return 1;
    }
    tmp = ({});
    foreach(ob in obs){
        int value;

        if( !((string)ob->GetShort()) ) continue;
        if( !((int)ob->GetVendorType() & GetVendorType()) ){
            eventForce("say I do not buy things like " +
              (string)ob->GetShort());
            continue;
        }
        cost = to_int(ob->GetBaseCost(GetLocalCurrency()));
        value = to_int(ceil(GetValue(ob, who)));
        if(ob->GetValue()) bargain = 1;
        else bargain = 0;
        if(!bargain) value = cost;

        if( !value ){
            eventForce("say " + (string)ob->GetShort() + " is worthless!");
            continue;
        }
        if( !((int)ob->CanSell(who)) ){
            eventForce("say You cannot sell " + (string)ob->GetShort() +".");
            continue;
        }
        if( sizeof(filter(all_inventory(sroom),
              (: $1->GetShort() == (string)$(ob)->GetShort() :)))
          > 3 ){
            if( (int)this_player()->AddCurrency(GetLocalCurrency(),value) == -1 ){
                eventForce("say you cannot carry "+value+" "+
                  GetLocalCurrency()+"!");
                ob->eventMove(environment());
                continue;
            }
            eventForce("say " + (string)ob->GetShort() + "! Excellent!");
            if(bargain) who->AddSkillPoints("bargaining", value*5);
            message("my_action", "You sell " + (string)ob->GetShort() + ".", who);
            message("other_action", capitalize((string)who->GetKeyName()) + " sells " +
              (string)ob->GetShort() + ".", environment(),
              ({ who, this_object() }));
            ob->eventDestruct();
            return 1;
        }
        eventForce("say " + (string)ob->GetShort() + "! Excellent!");
        if( !((int)ob->eventMove(sroom)) ){
            eventForce("say I cannot seem to carry that");
            return 1;
        }
        if( (int)this_player()->AddCurrency(GetLocalCurrency(), value) == -1 ){
            eventForce("say you cannot carry "+value+" "+
              GetLocalCurrency()+"!");
            ob->eventMove(environment());
            continue;
        }
        if(bargain) who->AddSkillPoints("bargaining", value*5);
        tmp += ({ ob });
        message("my_action", "You sell " + (string)ob->GetShort() + ".", who);
        message("other_action", capitalize((string)who->GetKeyName()) + " sells " +
          (string)ob->GetShort() + ".", environment(),
          ({ who, this_object() }));
    }
    if( !sizeof(tmp) )
        eventForce("say I am sorry, " + capitalize((string)who->GetKeyName()) + ", "
          "that we could not come to a better agreement.");
    else map(tmp, function(object ob){
              if( (int)ob->GetDestroyOnSell() )
                  ob->eventDestruct();
            });
          return 1;
      }

        int cmdShow(object who, string args){
        object ob, sroom;
        int x;

        if( !args || args == "" ){
            eventForce("say show you what?");
            return 1;
        }
        if( !(sroom = load_object(StorageRoom)) ){
            eventForce("say I am having troubles right now");
            return 1;
        }
        if( x = to_int(args) ){
            object *obs;
            object *obs2;
            string *list2;
            int maxi;

            x--;
            obs = all_inventory(sroom);
            maxi = sizeof(obs);
            list2 = ({(obs[0]->GetKeyName())});
            for(int counter = 1;counter < maxi;++counter){
                if(member_array((obs[counter]->GetKeyName()),list2) < 0){
                    list2 += ({ ( obs[counter]->GetKeyName()) });
                }
            }
            obs2 = ({ present(list2[0],sroom) });
            maxi = sizeof(list2);
            for(int counter = 1;counter < maxi;++counter){
                obs2 += ({ present(list2[counter],sroom) });
            }
            if((x >= 0) && (x < sizeof(obs2))){
                ob = obs2[x];
            }
        }
        else ob = present(args = lower_case(args), sroom);
        if( !ob ){
            eventForce("say I have no such thing to show you");
            return 1;
        }
        message("other_action", capitalize(GetKeyName())+" shows you "+
          (string)ob->GetShort()+".", who);
        message("system", (string)ob->GetLong(), who);
        return 1;
    }

    int cmdBrowse(object who, string args){
        object *obs;
        object *obs2;
        string *list2;
        string *list;
        object sroom;
        int i, ii, maxi, number;

        if( !args || args == "" ) args = "all";
        if( !(sroom = load_object(StorageRoom)) ){
            eventForce("say I am having terrific difficulties today");
            return 1;
        }
        if( !(maxi = sizeof(obs = filter(all_inventory(sroom), (: !userp($1) :) ))) ){
            eventForce("say I have nothing to sell right now.");
            return 1;
        }
        list = ({ "item #  Description                         Price", "" });
        list2 = ({(obs[0]->GetKeyName())});
        for(int counter = 1;counter < maxi;++counter){
            if(member_array((obs[counter]->GetKeyName()),list2) < 0){
                list2 += ({ ( obs[counter]->GetKeyName()) });
            }
        }
        obs2 = ({});
        foreach(object tempob in obs){
            string *base_names = ({});
            foreach( object tempob2 in obs2 ) base_names += ({ base_name(tempob2) });
            if(!sizeof(obs2)){
                obs2 = ({tempob});
            }
            else if(member_array(base_name(tempob), base_names) == -1) obs2 += ({ tempob });
        }
        maxi = sizeof(obs2); 
        i = (int)this_player()->GetScreen()[0];
        if(number = to_int(args)){
            if((number > 0) && (number <= maxi)){
                while( i-- ) list[1] += "_";
                list += ({ sprintf("%d      %:-35s %d", number, (string)obs2[(number - 1)]->GetShort(), GetCost(obs2[(number - 1)],who)) });
                this_player()->eventPage(list);
                return 1;
            }
        }

        while( i-- ) list[1] += "_";
        for(ii=0; ii < maxi; ii++){
            int ok;
            int gat;

            ok = 0;
            gat = (int)(obs2[ii]->GetArmorType());
            switch(args){
            case "all": ok = 1; break;
            case "weapon": case "weapons":
                break;
            case "armor": case "armors":
                if(obs2[ii]->GetVendorType() == 8){
                    ok = 1;
                }
                break;
            case "bag": case "bags":
                ok = (int)obs2[ii]->GetProperty("bag");
                break;
            case "ring": case "rings":
                ok = gat & A_RING;
                break;
            case "glove": case "gloves":
                ok = gat & (A_GLOVE | A_LONG_GLOVE);
                break;
            case "boot": case "boots":
                ok = gat & (A_BOOT | A_LONG_BOOT);
                break;
            case "sock": case "socks":
                ok = gat & (A_SOCK | A_LONG_SOCK);
                break;
            case "helm": case "helmet":
                ok = gat & A_HELMET;
                break;
            case "visor": case "visors":
                ok = gat & A_VISOR;
                break;
            case "pants":
                ok = gat & A_PANTS;
                break;
            case "shirt": case "shirts":
                ok = gat & A_SHIRT;
                break;
            case "cloak": case "cloaks":
                ok = gat & A_CLOAK;
                break;
            case "belt": case "belts":
                ok = gat & A_BELT;
                break;
            case "vest": case "vests":
                ok = gat & A_VEST;
                break;
            case "shield": case "shields":
                ok = gat & A_SHIELD;
                break;
            case "body armor": case "body armors":
                ok = gat & A_BODY_ARMOR;
                break;
            case "blunt": case "knife": case "blade": case "projectile":
            case "blunts": case "knives": case "blades": case "projectiles":
                ok = ((string)obs2[ii]->GetWeaponType() == args) ||
                (pluralize((string)obs2[ii]->GetWeaponType()) == args);
                break;
            default:
                ok = (int)obs2[ii]->id(args);
                break;
            }
            if( !ok ) continue;
            ok = GetCost(obs2[ii], who);
            if(!ii) ii = 0;
            list += ({ sprintf("%d      %:-35s %d", (ii+1), (string)obs2[ii]->GetShort(), to_int(ok)) });
        }
        if( !sizeof(list) ){
            eventForce("frown");
            eventForce("say I have nothing like that to sell.");
            return 1;
        }
        this_player()->eventPage(list);
        return 1;
    }

    int cmdAppraise(object who, string args){
        object ob;
        int x,cost;

        if( !args || args == "" ){
            eventForce("say appraise what?");
            return 1;
        }
        if( !(ob = present(args = lower_case(args), who)) ){
            eventForce("say You have no such thing!");
            return 1;
        }
        if( !((int)ob->GetVendorType() & GetVendorType()) ){
            eventForce("say I have no use for " + (string)ob->GetShort());
            return 1;
        }
        if( LocalCurrency != query_base_currency() ){
            cost=to_int(ob->GetBaseCost() / ECONOMY_D->__Query(LocalCurrency,"rate"));
        }
        else cost=to_int(floor(ob->GetBaseCost()));
        if(!cost || cost < 1){
            eventForce("say " + capitalize((string)who->GetKeyName()) + ", I will not buy "
              "that worthless thing from you.");
            return 1;
        }
        else x=cost;
        eventForce("say " + capitalize((string)who->GetKeyName()) + ", I will offer "
          "you " + x + " " + GetLocalCurrency() + " for " +
          (string)ob->GetShort());
        return 1;
    }

    int cmdPrice(object who, string args){
        object *obs;
        string *list2;
        object *obs2;
        object ob, sroom;
        int x;
        int maxi;

        if( !args || args == "" ){
            eventForce("say price what?");
            return 1;
        }
        if( !(sroom = load_object(StorageRoom)) ){
            eventForce("say today is not really a good day for me");
            return 0;
        }
        obs = all_inventory(sroom);
        obs2 = ({});
        foreach(object tempob in obs){
            string *base_names = ({});
            foreach( object tempob2 in obs2 ) base_names += ({ base_name(tempob2) });
            if(!sizeof(obs2)){
                obs2 = ({tempob});
            }
            else if(member_array(base_name(tempob), base_names) == -1) obs2 += ({ tempob });
        }
        maxi = sizeof(obs2);
        if( x = to_int(args) ){
            list2 = ({(obs2[0]->GetKeyName())});
            for(int counter = 1;counter < maxi;++counter){
                if(member_array((obs2[counter]->GetKeyName()),list2) < 0){
                    list2 += ({ ( obs2[counter]->GetKeyName()) });
                }
            }
            maxi = sizeof(list2);
            ob = obs2[x-1];
        }
        else ob = present(args = lower_case(args), sroom);
        if(!ob) foreach(object tempob in obs2) 
            if(answers_to(args,tempob)) ob = tempob;
        if( !ob ){
            eventForce("say I have no such thing!");
            return 1;
        }
        if( !(x = to_int(ceil(GetCost(ob, this_player())))) ){
            eventForce("say that thing has no value!");
            return 1;
        }
        eventForce("say " + capitalize((string)who->GetKeyName()) + ", I will take " +
          x + " " + GetLocalCurrency() + " for " +
          (string)ob->GetShort());
        return 1;
    }

    mixed eventAsk(object who, string str){
        object *obs;
        object ob;
        string cmd, args, tmp;

        if( !str || str == "" ){
            eventForce("say what do you want from me?");
            return 1;
        }
        if( sscanf(str, "%s %s", cmd, args) != 2 ){
            cmd = str;
            args = 0;
        }
        switch(cmd){
        case "appraise":
            return cmdAppraise(who, args);

        case "browse":
            return cmdBrowse(who, args);

        case "buy":
            if( str == "all" )
                obs = filter(all_inventory(who), (: (int)$1->CanSell() :));
            else {
                if( !(ob = present(args, who)) ){
                    eventForce("say Get out of here you cheat!");
                    eventForce("bump " + (string)this_player()->GetKeyName());
                    return 1;
                }
                obs = ({ ob });
            }
            return eventBuy(who, obs);

        case "price":
            return cmdPrice(who, args);

        case "sell":
            if( (tmp = CanSell(who, args)) == 1 ) return eventSell(who, args);
            else if( stringp(tmp) ) eventForce("say " + tmp);
            else {
                return 0;
            }

        case "show":
            return cmdShow(who, args);

        default:
            eventForce("say I am not quite sure what you want from me");
        }
    }

    mixed eventSell(object who, mixed what){
        object ob, sroom;
        object *obs;
        string *list2;
        object *obs2;
        int cost,number,maxi;

        sroom = load_object(StorageRoom);
        obs = filter(all_inventory(sroom), (: !userp($1) :));
        obs2 = ({});
        foreach(object tempob in obs){
            string *base_names = ({});
            foreach( object tempob2 in obs2 ) base_names += ({ base_name(tempob2) });
            if(!sizeof(obs2)){
                obs2 = ({tempob});
            }
            else if(member_array(base_name(tempob), base_names) == -1) obs2 += ({ tempob });
        }
        maxi = sizeof(obs2);
        if(number = to_int(what)){
            number = number - 1;
            list2 = ({(obs2[0]->GetKeyName())});
            for(int counter = 1;counter < maxi;++counter){
                if(member_array((obs2[counter]->GetKeyName()),list2) < 0){
                    list2 += ({ ( obs2[counter]->GetKeyName()) });
                }
            }
            maxi = sizeof(list2);
            if((number >= 0) && (number < sizeof(obs2))){
                ob = obs2[number];
            } else {
                eventForce("say I have nothing like that to sell to you.");
                return 1;
            }      
        } else {
            if( !(ob = present(what, sroom))) 
                foreach(object tempob in obs2) 
                if(answers_to(what,tempob)) ob = tempob;
            if(!ob || userp(ob)){
                eventForce("say I have nothing like that to sell");
                return 1;
            }
        }
        cost=to_int(ob->GetBaseCost(GetLocalCurrency()));
        if(!cost || cost < 0){
            cost = 0; 
            cost = to_int(ob->GetValue());
        }
        if(who->GetCurrency(GetLocalCurrency()) < cost){
            eventForce("say You don't have enough "+GetLocalCurrency()+
              " to buy that.");
            return 1;
        }
        if( !((int)ob->eventMove(this_object())) ){
            message("error", "An error occurred moving the object, use bug -r.",
              who);
            return 1;
        }
        eventForce("say here is " + (string)ob->GetShort() + " for " + to_int(cost) +
          " " + GetLocalCurrency() + "!");
        eventForce("give " + (string)ob->GetKeyName() + " to " + (string)who->GetKeyName());
        if( environment(ob) == this_object() ){
            eventForce("say you cannot carry that!");
            eventForce("drop " + (string)ob->GetKeyName());
        }
        if(bargain) who->AddSkillPoints("bargaining", random(to_int(floor(cost))));
        who->AddCurrency(GetLocalCurrency(), -cost);
        return 1;
    }

    int GetCost(object ob, object who){
        int x, mod,cost;

        cost=ob->GetBaseCost(LocalCurrency);
        if(cost && cost > 0) return cost;

        if( Costs[who] && Costs[who][ob] ) return Costs[who][ob];    
        x = ob->GetValue(GetLocalCurrency());
        mod = (int)who->GetSkillLevel("bargaining") - GetSkillLevel("bargaining");
        if( mod < -90 ) mod = -90;
        if( mod > 90 ) mod = 90;
        x = (x * (100 - mod))/100;
        who->AddSkillPoints("bargaining", x);
        if( !Costs[who] ) Costs[who] = ([ ob : x ]);
        else Costs[who][ob] = x;
        return x;
    }

    int GetValue(object ob, object who){
        int x, mod;

        if( Values[who] && Values[who][ob] ) return Values[who][ob];
        x = ob->GetValue(GetLocalCurrency());
        mod = (int)who->GetSkillLevel("bargaining") - GetSkillLevel("bargaining");
        if( mod < -90 ) mod = -90;
        if( mod > 90 ) mod = 90;
        x = (x * (100 - -mod)) / 100;
        who->AddSkillPoints("bargaining", x);
        if( !Values[who] ) Values[who] = ([ ob : x ]);
        else Values[who][ob] = x;
        return x;
    }

    string SetLocalCurrency(string str){ return (LocalCurrency = str); }

    string GetLocalCurrency(){ return LocalCurrency; }

    string SetStorageRoom(string room){ return (StorageRoom = room); }

    string GetStorageRoom(){ return StorageRoom; }

    int SetMaxItems(int x){ return (MaxItems = x); }

    int GetMaxItems(){ return MaxItems; }

    int SetVendorType(int x){ return (VendorType = x); }

    int GetVendorType(){ return VendorType; }





